package cn.krund.lyc.hotlerobot.Ros.service;

import android.util.Log;

import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import cn.krund.lyc.hotlerobot.Ros.service.communication.ClientSocketRunnable;
import cn.krund.lyc.hotlerobot.Ros.service.communication.HeartBeatRunnable;
import cn.krund.lyc.hotlerobot.Ros.service.communication.IRosCommunicationListener;
import cn.krund.lyc.hotlerobot.Ros.service.communication.RosSocketRunnable;
import cn.krund.lyc.hotlerobot.Ros.service.communicationinfo.RosProtocolInfo;
import cn.krund.lyc.hotlerobot.utils.KrundLog;

/**
 * @包名: cn.krund.lyc.hotlerobot.robot.service
 * @作者: 刘育成
 * @时间: 2018/4/2  15:17
 * @org: 克路德人工智能
 * @描述: TODO
 * @fileName: SocketServer
 */

public class SocketServer implements Runnable {
    private ExecutorService mService = null;
    private int mPort;    //端口号
    private boolean isCommunicationRun;     // 是否在进行通讯
    private IRosCommunicationListener mRosCommunicationListener;
    private Socket mRosSocket;
    private ServerSocket serverSocket = null;

    public SocketServer(int port) {
        this.mPort = port;
        this.mService = Executors.newCachedThreadPool();
    }

    public IRosCommunicationListener getRosCommunicationListener() {
        return mRosCommunicationListener;
    }

    public void setRosCommunicationListener(IRosCommunicationListener rosCommunicationListener) {
        this.mRosCommunicationListener = rosCommunicationListener;
    }

    /**
     * 开始通讯
     */
    public void startRosCommunication() {
        if (isCommunicationRun) return;
        Thread thread = new Thread(this);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                if (getRosCommunicationListener() != null) {
                    getRosCommunicationListener().exceptionHandler(t, e);
                }
            }
        });
        thread.start();

    }

    /**
     * 停止通讯
     */
    public void stopRosCommunication() {
        this.isCommunicationRun = false;
        mService.shutdownNow();
        if (serverSocket != null && !serverSocket.isClosed()) {
            try {
                serverSocket.close();
                serverSocket = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void run() {
        this.isCommunicationRun = true;
        try {
            serverSocket = new ServerSocket(mPort);
        } catch (IOException e) {
            e.printStackTrace();
        }
        while (isCommunicationRun) {
            Socket socket;
            try {

                mRosSocket = serverSocket.accept();
                mRosSocket.setSoTimeout(10000);
                mRosSocket.setOOBInline(true);

                String ip = mRosSocket.getInetAddress().getHostAddress();
                if (getRosCommunicationListener() != null) {
                    this.getRosCommunicationListener().onConnectComplete(ip, mRosSocket.getPort());
                }
                Log.e("lyc>>>", "ip" + ip);
                if (ip.equals("127.0.0.1")) {
//                    this.mRosSocket = socket;
                    KrundLog.d("lyc::::", "Ros连接成功");
                    mService.execute(new RosSocketRunnable(mRosSocket, mRosCommunicationListener));
                    mService.execute(new RosSocketHeartBeatRunnable());
                } else {
                    mService.execute(new ClientSocketRunnable(mRosSocket, mRosCommunicationListener));
                    mService.execute(new HeartBeatRunnable(mRosSocket, mRosCommunicationListener));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            if (serverSocket != null) {
                serverSocket.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送信息
     *
     * @param rosProtocolInfo
     * @return
     */
    public boolean sendMessage(RosProtocolInfo rosProtocolInfo) {
        if (isCommunicationRun || this.mRosSocket == null) return false;
        try {
            DataOutputStream printStream = new DataOutputStream(this.mRosSocket.getOutputStream());
            printStream.write(rosProtocolInfo.toBytes());
            printStream.flush();
            return true;
        } catch (Exception e) {
            try {
                this.mRosSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            this.mRosSocket = null;
            return false;
        }
    }

    public boolean sendBytes(byte[] bytes, int off, int len) {
        if (!isCommunicationRun || this.mRosSocket == null) return false;
        try {
            DataOutputStream printStream = new DataOutputStream(this.mRosSocket.getOutputStream());
            printStream.write(bytes, off, len);
            printStream.flush();
            return true;
        } catch (Exception e) {
            try {
                this.mRosSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            this.mRosSocket = null;
            return false;
        }
    }

    public boolean sendBytes(byte[] bytes) {
        if (!isCommunicationRun || this.mRosSocket == null) return false;
        try {
            DataOutputStream printStream = new DataOutputStream(this.mRosSocket.getOutputStream());
            printStream.write(bytes);
            printStream.flush();
            return true;
        } catch (Exception e) {
            try {
                this.mRosSocket.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            this.mRosSocket = null;
            return false;
        }
    }

    class RosSocketHeartBeatRunnable implements Runnable {
        @Override
        public void run() {
            try {
                while (mRosSocket.isConnected() && !mRosSocket.isClosed()) {
                    DataOutputStream printStream = new DataOutputStream(mRosSocket.getOutputStream());
                    printStream.write(0xFF);
                    printStream.flush();
                    Thread.sleep(5000);
                }
            } catch (Exception e) {
                try {
                    if (mRosSocket != null) {
                        mRosSocket.close();
                        mRosSocket = null;
                    }
                } catch (IOException e1) {
                    e1.printStackTrace();
                }

            }
        }
    }
}
